package topcbl.game;

import java.util.HashMap;
import java.util.Random;
import java.util.Vector;

import topcbl.gamewithme.R;
import topcbl.room.MainActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

enum Direction {
	UP, DOWN, LEFT, RIGHT
}

/**
 * Class vẽ bàn cờ cho Domino
 * 
 * @author baolong
 * 
 */
public class DominoChessBoard extends SurfaceView implements
		SurfaceHolder.Callback {
	Paint mPaint = null;
	SurfaceHolder mSurfaceHolder = null;
	Canvas mCanvas = null;
	Canvas mDrawBlockCanvas;
	Bitmap mHoldBlockBitmap;
	Context context;
	public static final int WIDTH_OF_BLOCK = 45;
	public static final int HEIGHT_OF_BLOCK = 89;
	public static final int SEPARATE_BLOCK = 0;

	// position where block is put
	int[] mLeftPosition = new int[2];
	int[] mRightPosition = new int[2];

	// the number of block domino at last of left and right side
	int mLeftNum = -1, mRightNum = -1;
	Direction mLeftDirection = Direction.LEFT; // direction of left side
	Direction mRightDirection = Direction.RIGHT; // direction of right side

	// data
	boolean mCanPlay = false;
	int mChoosingBlock = -1;
	// The hashmap in vector have key: 1st, 2nd and status
	Vector<HashMap<String, Integer>> mTakenBlocks = new Vector<HashMap<String, Integer>>();
	int[] mAllBlock = new int[56]; // bộ bài

	public DominoChessBoard(Context context) {
		super(context);
		mSurfaceHolder = this.getHolder();
		mSurfaceHolder.addCallback(this);
		this.context = context;
	}

	public DominoChessBoard(Context context, AttributeSet attrs) {
		super(context, attrs);
		mSurfaceHolder = this.getHolder();
		mSurfaceHolder.addCallback(this);
		this.context = context;
	}

	public DominoChessBoard(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mSurfaceHolder = this.getHolder();
		mSurfaceHolder.addCallback(this);
		this.context = context;
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setColor(Color.RED);
		mLeftPosition[0] = this.getWidth() >> 1;
		mLeftPosition[1] = this.getHeight() >> 1;
		mRightPosition[0] = this.getWidth() >> 1;
		mRightPosition[1] = this.getHeight() >> 1;
		mHoldBlockBitmap = Bitmap.createBitmap(this.getWidth() << 2,
				this.getHeight() << 2, Bitmap.Config.ARGB_8888);
		mDrawBlockCanvas = new Canvas(mHoldBlockBitmap);
		draw();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
	}

	public void draw() {
		mCanvas = mSurfaceHolder.lockCanvas();
		mCanvas.drawColor(getResources().getColor(R.color.background));
		mCanvas.drawBitmap(mHoldBlockBitmap, 0, 0, null);
		mSurfaceHolder.unlockCanvasAndPost(mCanvas);
	}

	float x1, y1, x2, y2, dx = 0, dy = 0;

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			x1 = event.getX();
			y1 = event.getY();
			if (mCanPlay && mChoosingBlock != -1) {
				int num1 = mTakenBlocks.get(mChoosingBlock).get("1st");
				int num2 = mTakenBlocks.get(mChoosingBlock).get("2nd");
				if (mLeftNum == -1) { // first play
					if (MainActivity.mServer != null) {
						MainActivity.mServer.getRoom().send2AllPlayer(
								"FIRSTPLAY_" + num1 + ":" + num2);
					} else {
						MainActivity.mClient.getOutput().println(
								"FIRSTPLAY_" + num1 + ":" + num2);
					}
					affectDominoActivity();
					affectChessBoard(num1 + ":" + num2, true);
				} else { // next play
					// put domino on left side
					if (Math.sqrt(Math.pow(x1 - dx - mLeftPosition[0], 2)
							+ Math.pow(y1 - dy - mLeftPosition[1], 2)) < HEIGHT_OF_BLOCK
							&& (mLeftNum == num1 || mLeftNum == num2)) {
						String data = num1 + ":" + num2 + ":" + "left";
						if (MainActivity.mServer != null) { // is Server
							MainActivity.mServer.getRoom().send2AllPlayer(
									"PLAY_" + data);
						} else { // is Client
							MainActivity.mClient.getOutput().println(
									"PLAY_" + data);
						}
						affectDominoActivity();
						affectChessBoard(data, false);
						// put domino on right side
					} else if (Math.sqrt(Math.pow(x1 - dx - mRightPosition[0],
							2) + Math.pow(y1 - dy - mRightPosition[1], 2)) < HEIGHT_OF_BLOCK
							&& (mRightNum == num1 || mRightNum == num2)) {
						String data = num1 + ":" + num2 + ":" + "right";
						if (MainActivity.mServer != null) { // is Server
							MainActivity.mServer.getRoom().send2AllPlayer(
									"PLAY_" + data);
						} else { // is Client
							MainActivity.mClient.getOutput().println(
									"PLAY_" + data);
						}
						affectDominoActivity();
						affectChessBoard(data, false);
					}
				}
			}
			break;
		case MotionEvent.ACTION_MOVE:
			x2 = event.getX();
			y2 = event.getY();
			mCanvas.translate(x2 - x1, y2 - y1);
			dx += x2 - x1;
			dy += y2 - y1;
			draw();
			x1 = x2;
			y1 = y2;
			break;

		}
		return true;
	}

	/*
	 * Put first block on chessboard, data example 3:2
	 */
	public void putFirstBlockOnChessBoard(String data) {
		String[] splitedData = data.split(":");
		int num1 = Integer.parseInt(splitedData[0]);
		int num2 = Integer.parseInt(splitedData[1]);
		// case put same number block e.t 6:6 3:3
		if (num1 == num2) {
			drawBlockSameNumber(num1, "left");
			mLeftNum = num1;
			mRightNum = num1;
		} else { // case difference number e.t 4:0
			mLeftPosition[0] -= HEIGHT_OF_BLOCK + SEPARATE_BLOCK;
			drawBlock(num1, num2, mLeftPosition[0], mLeftPosition[1], -90);
			mLeftNum = num1 < num2 ? num1 : num2;
			mRightNum = num1 > num2 ? num1 : num2;
		}
	}

	/*
	 * Put block on chessBoard, data example 3:2:left
	 */
	public void putOnChessBoard(String data) {
		String[] splitedData = data.split(":");
		int num1 = Integer.parseInt(splitedData[0]);
		int num2 = Integer.parseInt(splitedData[1]);
		String side = splitedData[2];
		// case put same number block e.t 6:6 3:3
		if (num1 == num2) {
			drawBlockSameNumber(num1, side);
		} else { // case difference number e.t 4:0
			drawBlockDifferenceNumber(num1, num2, side);
		}
	}

	private void drawBlockDifferenceNumber(int num1, int num2, String side) {
		Direction curDirection, newDirection;
		int[] position;
		int curNum;
		if (side.equals("left")) {
			curDirection = mLeftDirection;
			newDirection = getNewDirection(curDirection, side);
			mLeftDirection = newDirection;
			position = mLeftPosition;
			curNum = mLeftNum;
			mLeftNum = mLeftNum == num1 ? num2 : num1;
		} else {
			curDirection = mRightDirection;
			newDirection = getNewDirection(curDirection, side);
			mRightDirection = newDirection;
			position = mRightPosition;
			curNum = mRightNum;
			mRightNum = mRightNum == num1 ? num2 : num1;
		}

		switch (curDirection) {
		case UP:
			switch (newDirection) {
			case UP:
				position[1] -= HEIGHT_OF_BLOCK + SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 180 : 0);
				break;
			case LEFT:
				position[0] -= HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK;
				position[1] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 90 : -90);
				break;
			case RIGHT:
				position[1] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? -90 : 90);
				position[0] += HEIGHT_OF_BLOCK;
				break;
			default:
			}
			break;
		case DOWN:
			switch (newDirection) {
			case DOWN:
				position[1] += SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 0 : 180);
				position[1] += HEIGHT_OF_BLOCK;
				break;
			case LEFT:
				position[0] -= HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK;
				position[1] += SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 90 : -90);
				break;
			case RIGHT:
				position[1] += SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? -90 : 90);
				position[0] += HEIGHT_OF_BLOCK;
				break;
			default:
			}
			break;
		case LEFT:
			switch (newDirection) {
			case UP:
				position[0] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
				position[1] -= HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 180 : 0);
				break;
			case DOWN:
				position[0] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 0 : 180);
				position[1] += HEIGHT_OF_BLOCK;
				break;
			case LEFT:
				position[0] -= HEIGHT_OF_BLOCK + SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 90 : -90);
				break;
			default:
			}
			break;
		case RIGHT:
			switch (newDirection) {
			case UP:
				position[1] -= HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK;
				position[0] += SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 180 : 0);
				break;
			case DOWN:
				position[0] += SEPARATE_BLOCK;
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? 0 : 180);
				position[1] += HEIGHT_OF_BLOCK;
				break;
			case RIGHT:
				drawBlock(num1, num2, position[0], position[1],
						curNum == (num1 < num2 ? num1 : num2) ? -90 : 90);
				position[0] += HEIGHT_OF_BLOCK + SEPARATE_BLOCK;
				break;
			default:
			}
			break;
		}
	}

	private void drawBlockSameNumber(int num, String side) {
		Direction curDirection;
		int[] position;
		if (side.equals("left")) {
			curDirection = mLeftDirection;
			position = mLeftPosition;
		} else {
			curDirection = mRightDirection;
			position = mRightPosition;
		}
		switch (curDirection) {
		case UP:
			position[1] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
			position[0] -= (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			drawBlock(num, num, position[0], position[1], 90);
			position[0] += (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			break;
		case DOWN:
			position[1] += SEPARATE_BLOCK;
			position[0] -= (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			drawBlock(num, num, position[0], position[1], 90);
			position[1] += WIDTH_OF_BLOCK;
			position[0] += (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			break;
		case LEFT:
			position[0] -= WIDTH_OF_BLOCK + SEPARATE_BLOCK;
			position[1] -= (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			drawBlock(num, num, position[0], position[1], 0);
			position[1] += (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			break;
		case RIGHT:
			position[0] += SEPARATE_BLOCK;
			position[1] -= (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			drawBlock(num, num, position[0], position[1], 0);
			position[0] += WIDTH_OF_BLOCK;
			position[1] += (HEIGHT_OF_BLOCK - WIDTH_OF_BLOCK) / 2;
			break;

		}

	}

	private void drawBlock(int num1, int num2, int x, int y, int angle) {
		Bitmap hinh = BitmapFactory.decodeResource(getResources(),
				DominoActivity.getBlockImage(num1, num2));
		Matrix matrix = new Matrix();
		matrix.postRotate(angle);
		Bitmap rotateBitmap = Bitmap.createBitmap(hinh, 0, 0, hinh.getWidth(),
				hinh.getHeight(), matrix, true);
		mDrawBlockCanvas.drawBitmap(rotateBitmap, x, y, null);
		draw();
	}

	/*
	 * get direction from current direction and side that put block
	 */
	private Direction getNewDirection(Direction curDirection, String side) {
		Random random = new Random();
		int ranNum = random.nextInt(4);
		if (side.equals("left")) {
			switch (curDirection) {
			case LEFT:
				if (ranNum < 2)
					return Direction.LEFT;
				else if (ranNum == 2)
					return Direction.UP;
				else
					return Direction.DOWN;
			case UP:
				if (ranNum < 2)
					return Direction.UP;
				else
					return Direction.LEFT;
			case DOWN:
				if (ranNum < 2)
					return Direction.DOWN;
				else
					return Direction.LEFT;
			default:
				return curDirection;
			}
		} else {
			switch (curDirection) {
			case RIGHT:
				if (ranNum < 2)
					return Direction.RIGHT;
				else if (ranNum == 2)
					return Direction.UP;
				else
					return Direction.DOWN;
			case UP:
				if (ranNum < 2)
					return Direction.UP;
				else
					return Direction.RIGHT;
			case DOWN:
				if (ranNum < 2)
					return Direction.DOWN;
				else
					return Direction.RIGHT;
			default:
				return curDirection;
			}
		}

	}

	public void affectDominoActivity() {
		DominoActivity motherActivity = (DominoActivity) context;
		motherActivity.removeBlockBtn(mChoosingBlock);
		motherActivity.mNumberBlockOnHand--;
		if (motherActivity.mServerDomino != null) { // is server
			motherActivity.mServerDomino.wakeUpThead();
			// check win server
			if (motherActivity.mNumberBlockOnHand == 0) {
				MainActivity.mServer.getRoom().send2AllPlayer("LOSE_0");
				Toast.makeText(context, "Bạn là người thắng cuộc!^^",
						Toast.LENGTH_LONG).show();
				motherActivity.mServerDomino.interrupt();
			}
		} else if (motherActivity.mNumberBlockOnHand == 0) { // is client win
			MainActivity.mClient.getOutput().println("LOSE_0");
			Toast.makeText(context, "Bạn là người thắng cuộc!^^",
					Toast.LENGTH_LONG).show();
			motherActivity.mClientDomino.interrupt();
		}
	}

	private void affectChessBoard(String data, boolean isFirstPlay) {
		if (isFirstPlay)
			putFirstBlockOnChessBoard(data);
		else
			putOnChessBoard(data);
		mCanPlay = false;
		mTakenBlocks.get(mChoosingBlock).put("status", 0);
		mChoosingBlock = -1;
	}

	public int countPoint() {
		int result = 0;
		for (int i = 0; i < mTakenBlocks.size(); i++) {
			HashMap<String, Integer> hash = mTakenBlocks.get(i);
			// check block which isn't put on chessboard
			if (hash.get("status") == 1) {
				result += hash.get("1st");
				result += hash.get("2nd");
			}
		}
		return result;
	}

}
